package it.unicam.cs.cosy.bioshape.core.shapes;

import java.io.Serializable;

import javax.vecmath.Point3d;
import javax.vecmath.Tuple3d;

/**
 * The abstract base class for bounds objects. Bounds objects define a convex,
 * closed volume that is used for various intersection and culling operations.
 * Typically, as in this implementation, we can distinguish bounds which are
 * <i>boxes</i> or <i>spheres</i>.
 * 
 * @author Federico Buti
 */
public abstract class Bounds implements Serializable {

	/** Auto-generated Serial ID */
	private static final long serialVersionUID = -8134901555296043221L;
	static final int BOUNDING_BOX = 0x1;
	static final int BOUNDING_SPHERE = 0x2;
	int boundId = 0;

	/**
	 * Checks if the passed bounding value is completely contained, i.e. no
	 * feature is outside the bounding coordinates of the first bounding volume.
	 * 
	 * @param boundsObject
	 *            The bounding volume to check for containment
	 * @return {@code true} if the bounding volume is completely contained,
	 *         {@code false} otherwise
	 */
	public abstract boolean contains(Bounds boundsObject);

	/**
	 * Makes a copy of a bounds object.
	 */
	@Override
	protected abstract Object clone();

	/**
	 * Indicates whether the specified bounds object is equal to this Bounds
	 * object.
	 */
	@Override
	public abstract boolean equals(java.lang.Object bounds);

	/**
	 * Returns a hash code for this Bounds object based on the data values in
	 * this object.
	 */
	@Override
	public int hashCode() {
		return super.hashCode();
	}

	/**
	 * Test for intersection with another Bounds object. Uses Arvo's algorithm
	 * for AABB-sphere check, with the <i>quick rejections intertwined</i>
	 * performance tweak.
	 * 
	 * @param boundsObject
	 *            the bound that must be checked against this one
	 * @return {@code true} if two bounds intersect, {@code false} otherwise
	 */
	public abstract boolean intersect(Bounds boundsObject);

	/**
	 * Test for intersection with a point.
	 * 
	 * @param point
	 *            The {@code Point3d} against which the bounding is checked for
	 *            intersection
	 * @return {@code true} if the bounding intersect the point, {@code false}
	 *         otherwise
	 */
	public abstract boolean intersect(Tuple3d point);

	/**
	 * Sets the value of this Bounding object.
	 * 
	 * @param boundsObject
	 *            The bounding which provides the data to set this bounding
	 */
	public abstract void set(Bounds boundsObject);

	/**
	 * TODO forse si può togliere Returns the radius, defined as the maximum
	 * distance of any vertex of the bounding volume from its centre. Thus, in
	 * {@code BoundingBox} objects returns the radius of the
	 * 
	 * @return the radius of the bounding box
	 */
	public abstract double getRadius();

	/**
	 * The centre of the bounding shape is moved to the new point. All the
	 * points of the shape are moved accordingly.
	 * 
	 * @param point
	 *            The new centre of the bounding box
	 */
	public abstract void moveTo(Tuple3d point);

	/**
	 * The centre of the bounding shape is translated of the amount passed as
	 * parameter. All the points of the shape are moved accordingly.
	 * 
	 * @param offset
	 *            The new centre of the bounding box
	 */
	public abstract void translateOf(Tuple3d offset);

	/**
	 * The centre of the bounding shape is translated of the amount passed as
	 * parameter. All the points of the shape are moved accordingly.
	 * 
	 * @param x
	 *            The x-axis offset
	 * @param y
	 *            The new y-axis offset
	 * @param z
	 *            The new z-axis offset
	 */
	public abstract void translateOf(double x, double y, double z);

	/**
	 * The center of the bounding shape is moved to the new point. All the
	 * points of the shape are moved accordingly.
	 * 
	 * @param x
	 *            The new x-axis coordinate
	 * @param y
	 *            The new y-axis coordinate
	 * @param z
	 *            The new z-axis coordinate
	 */
	public abstract void moveTo(double x, double y, double z);

	// TODO: this methods can be added to implement affine transformations on
	// the bounding boxes. This feature is currently UNSUPPORTED.
	/**
	 * Modifies the bounding object so that it bounds the volume generated by
	 * transforming the given bounding object.
	 * 
	 * @param bounds
	 * @param trans
	 */
	// abstract void transform(Bounding bounds, Transform3D trans)
	/**
	 * Transforms this bounding object by the given matrix.
	 * 
	 * @param trans
	 */
	// abstract void transform(Transform3D trans)

	/**
	 * @param index
	 *            index of the coordinate value of the minimal point, to return
	 * @return the value of the chosen coordinate
	 */
	public abstract double getMin(int index);

	/**
	 * @param index
	 *            index of the coordinate value of the maximal point, to return
	 * @return the value of the chosen coordinate
	 */
	public abstract double getMax(int index);

	/**
	 * @return the center of the bounding volume
	 */
	public abstract Point3d getCenter();
}